/*
 * 异步流程控制工具函数
 * 用于控制异步函数的执行流程、并发管理和批量处理
 */

import { timerManager } from "../common";

/**
 * 串行执行异步任务
 * @template T - 任务返回类型
 * @param {Array<() => Promise<T>>} tasks - 要串行执行的异步任务数组
 * @returns {Promise<T[]>} 所有任务执行结果的Promise数组
 * @example
 * const results = await series([
 *   () => fetch('https://api.example.com/users/1'),
 *   () => fetch('https://api.example.com/users/2'),
 *   () => fetch('https://api.example.com/users/3')
 * ]);
 */
export async function series<T>(tasks: Array<() => Promise<T>>): Promise<T[]> {
  const results: T[] = [];
  for (const task of tasks) {
    const result = await task();
    results.push(result);
  }
  return results;
}

/**
 * 异步函数竞争执行，返回第一个完成的结果
 * @template T - Promise的解析类型
 * @param {Array<Promise<T>>} promises - 要竞争的Promise数组
 * @returns {Promise<T>} 第一个完成的Promise的结果
 * @example
 * const result = await race([
 *   fetch('https://api.example.com/endpoint1'),
 *   new Promise(resolve => setTimeout(() => resolve('timeout'), 3000))
 * ]);
 * // 如果请求在3秒内完成，返回请求结果；否则返回'timeout'
 */
export function race<T>(promises: Array<Promise<T>>): Promise<T> {
  return Promise.race(promises);
}

/**
 * 并行执行多个函数（可选择限制并发数）
 * @template {(...args: any[]) => Promise<any>} T - 异步函数类型
 * @param {T[]} funcs - 要执行的异步函数数组
 * @param {Object} [options] - 可选配置
 * @param {number} [options.concurrency] - 最大并发数，不设置则不限制
 * @returns {Promise<Array<Awaited<ReturnType<T>>>>} 所有函数执行结果的Promise数组
 * @example
 * // 无并发限制
 * const results1 = await parallel([
 *   () => Promise.resolve(1),
 *   () => Promise.resolve(2),
 *   () => Promise.resolve(3)
 * ]);
 * 
 * // 限制并发数为2
 * const results2 = await parallel([
 *   () => fetch('https://api.example.com/users/1'),
 *   () => fetch('https://api.example.com/users/2'),
 *   () => fetch('https://api.example.com/users/3'),
 *   () => fetch('https://api.example.com/users/4'),
 * ], { concurrency: 2 });
 */
export async function parallel<T extends (...args: any[]) => Promise<any>>(
  funcs: T[],
  options?: {
    concurrency?: number;
  }
): Promise<Array<Awaited<ReturnType<T>>>> {
  const concurrency = options?.concurrency;
  
  // 如果设置了并发限制，则使用限制并发的实现
  if (concurrency !== undefined && concurrency > 0) {
    if (concurrency <= 0) {
      throw new Error('并发数必须大于0');
    }

    const results: Array<Awaited<ReturnType<T>>> = [];
    let activeCount = 0;
    let currentIndex = 0;
    let isRejected = false;

    return new Promise((resolve, reject) => {
      const executeNext = async () => {
        // 如果所有函数已执行且没有活跃的执行器，解析结果
        if (currentIndex >= funcs.length && activeCount === 0) {
          resolve(results);
          return;
        }

        // 如果有错误或已达到并发限制，停止执行
        if (isRejected || activeCount >= concurrency || currentIndex >= funcs.length) {
          return;
        }

        const index = currentIndex;
        currentIndex++;
        activeCount++;

        try {
          // 执行当前函数
          const result = await funcs[index]();
          results[index] = result;
          activeCount--;
          executeNext();
        } catch (error) {
          // 发生错误时，拒绝整个Promise
          isRejected = true;
          activeCount--;
          reject(error);
        }
      };

      // 启动初始执行器
      while (activeCount < concurrency && currentIndex < funcs.length && !isRejected) {
        executeNext();
      }
    });
  }
  
  // 否则，使用无限制并发的实现（直接使用Promise.all）
  return Promise.all(funcs.map(fn => fn()));
}

/**
 * 批量处理函数
 * @template T - 输入数据类型
 * @template R - 处理结果类型
 * @param {(item: T) => Promise<R>} handler - 处理单个项目的函数
 * @param {T[]} items - 要处理的项目数组
 * @param {number} batchSize - 每批处理的项目数量
 * @param {number} [interval=0] - 批处理间隔时间(毫秒)
 * @returns {Promise<R[]>} 所有项目的处理结果数组
 * @example
 * const processItem = async (item) => {
 *   const response = await fetch(`https://api.example.com/process?data=${item}`);
 *   return response.json();
 * };
 * 
 * const results = await batch(processItem, [1, 2, 3, 4, 5, 6], 2, 1000);
 * // 每批处理2个项目，批之间间隔1秒
 */
export async function batch<T, R>(
  handler: (item: T) => Promise<R>,
  items: T[],
  batchSize: number,
  interval: number = 0
): Promise<R[]> {
  if (batchSize <= 0) {
    throw new Error('批量大小必须大于0');
  }

  const results: R[] = [];
  const batches: T[][] = [];

  // 将项目分成多个批次
  for (let i = 0; i < items.length; i += batchSize) {
    batches.push(items.slice(i, i + batchSize));
  }

  // 按批次处理项目
  for (let i = 0; i < batches.length; i++) {
    const batch = batches[i];
    
    // 并行处理当前批次的所有项目
    const batchResults = await Promise.all(batch.map(item => handler(item)));
    results.push(...batchResults);

    // 如果不是最后一批，等待指定的间隔时间
    if (i < batches.length - 1 && interval > 0) {
      await new Promise(resolve => {
        const timeoutId = timerManager.addTimer(interval, () => resolve(undefined));
        // 确保清除定时器
        return () => timerManager.removeTimer(timeoutId);
      });
    }
  }

  return results;
}